// 引包
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const {expressjwt} = require("express-jwt");
const md5 = require('md5');
const {ForbidenError, ServiceError, UnknownError} = require("./utils/errors");
const session = require("express-session");


// 默认读取项目跟目录下的.env里面的环境变量
require("dotenv").config();
// 捕获异步错误
require("express-async-errors");
// 引入数据库
require("./dao/db");


// 引入路由
var adminRouter = require('./routes/admin');


// 创建服务器实例
var app = express();

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: true,
  saveUninitialized: true
}))

/**
 * 下面这段代码的作用：
 * 请求时，会根据请求路径，从指定的目录中寻找是否存在该文件，如果存在，直接响应文件内容，而不在移交给后续的中间件
 * 静态资源
 */
const staticRoot = path.resolve(__dirname, "./public/dist");
app.use(express.static(staticRoot, {
  setHeaders(res, path) {
    if(!path.endsWith(".html")) {
      res.header("Cache-Control", `max-age=${3600*24}`);
    }
  }
}));


// 使用各种中间件
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


// 配置验证token接口
app.use(expressjwt({
  secret: md5(process.env.JWT_SECRET),
  algorithms: ['HS256'], // 新版本的expressJWT必须要求的算法
}).unless({
  // 需要排除的token验证路由
  path: [
    {"url": "/api/admin/login", methods: ["POST"]},
    {"url": "/res/captcha", methods: ["GET"]},
    {"url": "/api/banner", methods: ["GET"]},
    {"url": "/api/blogType", methods: ["GET"]},
    {"url": "/api/blog", methods: ["GET"]},
    {"url": /\/api\/blog\/\d/, methods: ["GET"]},
    {"url": "/api/project", methods: ["GET"]},
    {"url": "/api/message", methods: ["GET", "POST"]},
    {"url": "/api/comment", methods: ["GET", "POST"]},
    {"url": "/api/setting", methods: ["GET"]},
    {"url": "/api/about", methods: ["GET"]},
  ]
}))

// 使用路由中间件
app.use('/api/admin', adminRouter);
app.use('/res/captcha', require("./routes/captcha"));
app.use('/api/banner', require("./routes/banner"));
app.use('/api/upload', require("./routes/upload"));
app.use('/api/blogType', require("./routes/blogType"));
app.use('/api/blog', require("./routes/blog"));
app.use('/api/project', require("./routes/demo"));
app.use('/api/message', require("./routes/message"));
app.use('/api/comment', require("./routes/message"));
app.use('/api/setting', require("./routes/setting"));
app.use('/api/about', require("./routes/about"));


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  console.log(err.name, err.message)
  if(err.name === "UnauthorizedError") {
    // 说明是token验证错误，接下来抛出自定义错误信息
    res.send(new ForbidenError("未登录，或者登录已过期").toResponseJSON());
  } else if(err instanceof ServiceError) {
    res.send(err.toResponseJSON());
  } else {
    res.send(new UnknownError().toResponseJSON())
  }
});

module.exports = app;
